import { type Model, ObjectId } from 'mongoose';
import {
    ArticleCategory,
    ArticleCategoryDocument,
    CreateArticleCategoryDto,
    UpdateArticleCategoryDto,
} from '@ai/entity';
import { Cache, CACHE_MANAGER, CacheKey } from '@nestjs/cache-manager';
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { arrToTree } from '@/utils';
import { ArticleService } from '../article/article.service';
import { ARTICLE_CATEGORY_CACHE_KEY_MAP } from './config';

@Injectable()
export class ArticleCategoryService implements OnModuleInit {
    constructor(
        @Inject(CACHE_MANAGER) private cacheManager: Cache,
        private readonly articleService: ArticleService,
        @InjectModel(ArticleCategory.name) private readonly articleCategoryModel: Model<ArticleCategoryDocument>
    ) {}

    onModuleInit() {
        this.articleCategoryModel.init();
    }

    create(createArticleCategoryDto: CreateArticleCategoryDto) {
        return this.articleCategoryModel.create(createArticleCategoryDto);
    }

    async findAll(updateArticleCategoryDto: UpdateArticleCategoryDto = {}) {
        return arrToTree(await this.articleCategoryModel.find(updateArticleCategoryDto), 'parent');
    }

    async findOne(updateArticleCategoryDto: UpdateArticleCategoryDto = {}) {
        return this.articleCategoryModel.findOne(updateArticleCategoryDto);
    }

    @CacheKey(ARTICLE_CATEGORY_CACHE_KEY_MAP.FIND_LIST_BY_ARTICLES)
    async findListByArticles() {
        const getList = async (list: ObjectId[]) => {
            if (list.length === 0) return [];
            const ret = new Map();

            // 获取类目列表，并且在字典中存储
            const categoryList = await this.articleCategoryModel.find({ _id: { $in: list } });
            categoryList.forEach((item) => ret.set(item._id.toString(), item));

            // 获取父类目列表，并且判断是否已经在字典中存在
            const parentIdSet = new Set();
            categoryList.forEach((item) => item.parent && !ret.has(item.parent) && parentIdSet.add(item.parent));
            if (parentIdSet.size) {
                const parentList = await getList([...parentIdSet] as any[]);
                parentList.forEach((item) => ret.set(item._id.toString(), item));
            }

            return [...ret.values()];
        };

        const categories = await this.articleService.getAllCategories();
        const allCategory = await getList(categories);
        const ret = arrToTree(allCategory, 'parent');
        this.cacheManager.set(ARTICLE_CATEGORY_CACHE_KEY_MAP.FIND_LIST_BY_ARTICLES, ret);
        return ret;
    }

    findById(id: string) {}

    update(id: string, updateArticleCategoryDto: UpdateArticleCategoryDto) {
        return this.articleCategoryModel.findByIdAndUpdate(id, updateArticleCategoryDto);
    }

    remove(id: string) {
        return this.articleCategoryModel.findByIdAndDelete(id);
    }
}
